Golang JSON 序列化时动态忽略字段

在使用 JSON 时经常遇到需要忽略字段的情况,例如返回用户信息时不能返回密码,通常将注解 TAG 设为 json:"-" 即可:

1type User struct {
2	Account  string `json:"account"`
3	Password string `json:"-"`
4	Nickname string `json:"nickname"`
5}

但这样的静态配置会使字段在任何情况下都被忽略,有时希望可以根据需求动态的决定是否忽略某些字段。

可以通过反射将读取对象的字段名和字段值,过滤忽略的字段后存入一个 map[string]any 中,然后进行序列化:

1package utils
2
3import (
4	"encoding/json"
5	"reflect"
6)
7
8func JsonMarshalWithFilter(data any, ignore []string) ([]byte, error) {
9	filter := make(map[string]bool)
10	for i := range ignore {
11		name := ignore[i]
12		filter[name] = true
13	}
14	m := make(map[string]any)
15	metaType := reflect.TypeOf(data)
16	metaValue := reflect.ValueOf(data)
17	n := metaType.NumField()
18	for i := 0; i < n; i++ {
19		field := metaType.Field(i)
20		name := field.Tag.Get("json")
21		if filter[name] {
22			continue
23		}
24		value := metaValue.Field(i).Interface()
25		m[name] = value
26	}
27
28	return json.Marshal(m)
29}

调用:

1package main
2
3import "utils"
4
5type User struct {
6	Account  string `json:"account"`
7	Password string `json:"password"`
8	Nickname string `json:"nickname"`
9}
10
11func main() {
12	user := schema.User{
13		Account:  "hubenchang0515",
14		Password: "xxxxxxxxx",
15		Nickname: "planc0515",
16	}
17
18	data, _ := utils.JsonMarshalWithFilter(user, []string{"password"})
19	println(string(data))
20}
1$ go run .
2{"account":"hubenchang0515","nickname":"planc0515"}